package com.zhkc.wisdom.common.mybatis.encrypt.interceptor;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.zhkc.wisdom.common.mybatis.encrypt.annotation.SensitiveClass;
import com.zhkc.wisdom.common.mybatis.encrypt.utils.EncryptUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.sql.Statement;
import java.util.ArrayList;
import java.util.Objects;

/**
 * .
 *
 * @author kehong liu.
 */

@Slf4j
@Intercepts({ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = { Statement.class }) })
public class ResultSetInterceptor implements Interceptor {

	@Value("${zhkc.table.encryptPass:niqowehoqwe}")
	private String encryptPass;

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		// 取出查询的结果
		Object resultObject = invocation.proceed();
		if (Objects.isNull(resultObject)) {
			return null;
		}
		// 基于selectList
		extracted(resultObject);
		return resultObject;
	}

	private void extracted(Object resultObject) throws Exception {
		if (resultObject instanceof ArrayList) {
			ArrayList<?> resultList = (ArrayList<?>) resultObject;
			extracted(resultList);
			// 基于selectOne
		}
		else {
			if (needToDecrypt(resultObject)) {
				EncryptUtil.decrypt(resultObject, this.encryptPass);
			}
		}
	}

	private void extracted(ArrayList<?> resultList) throws Exception {
		if (!CollectionUtils.isEmpty(resultList) && needToDecrypt(resultList.get(0))) {
			for (Object result : resultList) {
				// 逐一解密
				EncryptUtil.decrypt(result, this.encryptPass);
			}
		}
	}

	private boolean needToDecrypt(Object object) {
		Class<?> objectClass = object.getClass();
		SensitiveClass sensitiveData = AnnotationUtils.findAnnotation(objectClass, SensitiveClass.class);
		return Objects.nonNull(sensitiveData);
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

}
